let _Vue = null; // 存储Vue 构造函数
export default class VueRouter {
  /**
   * 构造函数里初始化 VueRoute 的三个属性
   * - options
   * - routeMap // key: 路由地址，value: 路由对应的组件 根据路由地址 给出对应组件
   * - mode 设置路由模式是hash还是history ，这里默认是history
   * - data 响应式 // 通过 vue 实例提供的observable方法创建响应式对象
   * @param {*} params
   */
  constructor(params) {
    this.options = params;
    this.routeMap = {};
    this.mode = params.mode || "history";
    this.data = _Vue.observable({
      current: "/", // 存储当前的路由地址，默认是 ’/‘
    });
    
  }

  /**
   *
   * @param {*} Vue vue 的构造函数
   */
  static install(Vue) {
    // 1.判断当前插件是否已被安装
    if (VueRouter.install.installed) {
      return;
    }
    VueRouter.install.installed = true;
    // 2.把vue构造函数记录到全局变量
    _Vue = Vue;
    // 3.把创建Vue实例的时候传入的router对象注入到Vue 实例中
    // 混入
    _Vue.mixin({
      beforeCreate() {
        if (this.$options.router) {
          _Vue.prototype.$router = this.$options.router;
          this.$options.router.init();
        }
      },
    });
  }

  init() {
    this.createRouteMap();
    this.initComponents(_Vue);
    this.initEvent();
  }

  createRouteMap() {
    // 遍历路由规则解析成键值对，存储到routeMap 中

    this.options.routes.forEach((route) => {
      this.routeMap[route.path] = route.component;
    });
  }

  initComponents(Vue) {
    // 接受vue 的构造函数
    Vue.component("router-link", {
      props: {
        to: String,
      },
      //   template: '<a :href="to"><slot></slot></a>', // 使用插槽，将router-link 的内容替换slot，如果使用template 需要使用完整版自带编译器的vue 版本
      render(h) {
        // 这里的h 是vue 给的
        // 使用不带编译器,运行时版本的vue 这里需要使用render函数 ，

        return h(
          "a",
          {
            attrs: {
              href: this.to,
            },
            on: {
              // 给a标签添加点击事件
              click: clickHandler,
            },
          },
          [this.$slots.default]
        );
      },
      methods: {
        clickHandler(e) {
          if (this.isHistory()) {
            // 通过history.pushState()改变浏览器地址栏，不会给浏览器发送请求
            history.pushState({}, "", this.to);
          } else {
            window.location.hash = `#${this.to}`;
          }
          // 将当前路径记录到current 中, 因为current 是响应式，所以当它改变了 就会刷新响应的组件
          this.$router.data.current = this.to;
          e.preventDefault();
        },
      },
    });
    const self = this;
    Vue.component("router-view", {
      // 根据当前路由地址,在routeMap 中寻找对应的组件
      render() {
        const component = self.routeMap[self.data.current];
        return h(component); // h 函数将组件转换为虚拟dom
      },
    });
  }

  // 浏览器的前进后退处理 ，使用history 的 popState
  initEvent() {
    if (this.isHistory()) {

      // 注册popState 事件
      window.addEventListener("popstate", () => {
        // 将路由地址存到current 中
        this.data.current = window.location.path;
      });
    }else {
      window.addEventListener('hashchange', () => {
        this.data.current = window.location.hash.substr(1)
      })
    }
  }

  isHistory() {
    return this.mode === "history";
  }
}
